import { Injectable } from '@angular/core';
import { Observable,of } from 'rxjs';
import { catchError,map,tap } from 'rxjs/operators';

import { Hero } from './heroes/hero';
import { MessagesService } from './messages.service';
import { HttpClient, HttpHeaders } from '@angular/common/http';

@Injectable({
  providedIn: 'root'
})
export class HeroService {
  private heroesUrl = 'api/heroes';
  httpOptions = {
    headers: new HttpHeaders({ 'Content-Type': 'application/json' })
  };
  constructor(
    private messageService: MessagesService,
    private http: HttpClient,

  ) { }

  getHeroes(): Observable<Hero[]>{
    return this.http.get<Hero[]>(this.heroesUrl)
    .pipe(
      tap(_ => this.log("fetched heroes")),
      catchError(this.handleError<Hero[]>('getHeroes', []))
    );
  }

  getHero(id:number): Observable<Hero>{
    const url = `${this.heroesUrl}/${id}`;
    return this.http.get<Hero>(url)
      .pipe(
        tap(_ => this.log(`fetched hero id=${id}`)),
        catchError(this.handleError<Hero>(`getHero id=${id}`))
      );
  }

  updateHero(hero: Hero): Observable<any>{
      return this.http.put(this.heroesUrl,hero,this.httpOptions)
      .pipe(
        tap(_ => this.log(`update hero id=${hero.id}`)),
        catchError(this.handleError<any>(`updateHero id=${hero.id}`))
      )
  }

  addHero(hero:Hero):Observable<Hero>{
    return this.http.post(this.heroesUrl,hero,this.httpOptions)
      .pipe(
        tap((newHero:Hero) => this.log(`added hero w/ id=${newHero.id}`)),
        catchError(this.handleError<Hero>("addHero"))
      );
  }

  deleteHero(hero:Hero | number):Observable<Hero>{
    const id = typeof hero === 'number'? hero: hero.id;
    const url = `${this.heroesUrl}/${id}`;
    return this.http.delete<Hero>(url,this.httpOptions)
      .pipe(
        tap(_=> this.log(`delete hero w/ id=${id}`)),
        catchError(this.handleError<Hero>("deleteHero"))
      );
  }

  searchHeroes(term: string): Observable<Hero[]>{
    term = term.trim();
    if(!term){
      return of([]);
    }
    return this.http.get<Hero[]>(`${this.heroesUrl}/?name=${term}`)
      .pipe(
        tap(x=> x.length?
          this.log(`found heroes matching "${term}"`):
          this.log(`no heroes matching "${term}"`)
          ),
        catchError(this.handleError<Hero[]>("searchHeroes",[]))
      );
  }

  handleError<T>(operation = 'operation',result?: T){
    return (error: any): Observable<T> =>{
      console.error(error);
      this.log(`${operation} failed: ${error.message}`);
      return of(result as T);
    }
  }

  private log(message:string):void{
    this.messageService.add(`HeroService:${message}`);
  }
}
